package org.yystory.service;

import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Random;

import org.hibernate.Hibernate;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.ContextLoader;
import org.yystory.entity.Favourite;
import org.yystory.entity.Sequence;
import org.yystory.entity.Story;

public final class StoryService {
	private static final ApplicationContext applicationContext = ContextLoader
			.getCurrentWebApplicationContext();
	private static final SessionFactory sessionFactory = (SessionFactory) applicationContext
			.getBean("sessionFactory");

	@SuppressWarnings("rawtypes")
	public static final Story random() throws Exception {
		Session session = sessionFactory.openSession();
		try {
			Query query = session.createQuery("from Story");
			List list = query.list();
			int count = list.size();
			int id = new Random().nextInt(count);
			Story story = (Story) list.get(id);
			Hibernate.initialize(story);
			return story;
		} catch (Exception e) {
			if (session.isOpen()) {
				session.close();
			}
			throw e;
		}
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static final Story[] list(Date date) throws Exception {
		Session session = sessionFactory.openSession();
		try {
			Query query = session
					.createQuery("from Story where date between ? and ?");
			Date startDate = DateFormat.getDateInstance().parse(
					DateFormat.getDateInstance().format(date));
			Calendar calendar = Calendar.getInstance();
			calendar.setTime(startDate);
			calendar.add(Calendar.DATE, 1);
			Date endDate = calendar.getTime();
			query.setDate(0, date);
			query.setDate(1, endDate);
			List list = query.list();
			Hibernate.initialize(list);
			Story[] ret = new Story[list.size()];
			list.toArray(ret);
			return ret;
		} catch (Exception e) {
			if (session.isOpen()) {
				session.close();
			}
			throw e;
		}
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static final Sequence[] sequences(int storyId) throws Exception {
		Session session = sessionFactory.openSession();
		try {
			Query query = session
					.createQuery("from Sequence s where s.story.id=?");
			query.setInteger(0, storyId);
			List list = query.list();
			Hibernate.initialize(list);
			Sequence[] ret = new Sequence[list.size()];
			list.toArray(ret);
			return ret;
		} catch (Exception e) {
			if (session.isOpen()) {
				session.close();
			}
			throw e;
		}
	}

	public static final Sequence findSequence(int sequenceId) throws Exception {
		Session session = sessionFactory.openSession();
		try {
			Sequence sequence = (Sequence) session.load(Sequence.class,
					new Integer(sequenceId));
			Hibernate.initialize(sequence);
			return sequence;
		} catch (Exception e) {
			if (session.isOpen()) {
				session.close();
			}
			throw e;
		}
	}

	public static final int newTopic(String name, int userId, int length,
			byte[] data) throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		try {
			Story story = new Story();
			story.setDate(new Date(System.currentTimeMillis()));
			story.setName(name);
			story.setUserId(userId);
			session.save(story);
			Sequence sequence = new Sequence();
			sequence.setData(data);
			sequence.setDate(new Date(System.currentTimeMillis()));
			sequence.setEgg(0);
			sequence.setFlower(0);
			sequence.setOrder(1);
			sequence.setLength(length);
			sequence.setStory(story);
			sequence.setUserId(userId);
			session.save(sequence);
			session.getTransaction().commit();
			session.close();
			return story.getId();
		} catch (Exception e) {
			session.getTransaction().rollback();
			if (session.isOpen()) {
				session.close();
			}
			throw e;
		}
	}

	public static final int follow(int sequenceId, int userId, int length,
			byte[] data) throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		try {
			Sequence followed = (Sequence) session.load(Sequence.class,
					new Integer(sequenceId));
			Sequence sequence = new Sequence();
			sequence.setData(data);
			sequence.setDate(new Date(System.currentTimeMillis()));
			sequence.setEgg(0);
			sequence.setFlower(0);
			sequence.setLength(length);
			sequence.setOrder(followed.getOrder() + 1);
			sequence.setStory(followed.getStory());
			sequence.setUserId(userId);
			session.save(sequence);
			session.getTransaction().commit();
			session.close();
			return sequence.getId();
		} catch (Exception e) {
			session.getTransaction().rollback();
			if (session.isOpen()) {
				session.close();
			}
			throw e;
		}
	}

	public static final Story findStory(int sequenceId) throws Exception {
		Session session = sessionFactory.openSession();
		try {
			Sequence sequence = (Sequence) session.load(Sequence.class,
					new Integer(sequenceId));
			Story story = sequence.getStory();
			Hibernate.initialize(story);
			return story;
		} catch (Exception e) {
			if (session.isOpen()) {
				session.close();
			}
			throw e;
		}
	}

	public static final void favourite(int userId, int storyId, int sequenceId)
			throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		try {
			Query query = session
					.createQuery("from Favourite f where f.userId=? and f.story.id=? and f.sequence.id=?");
			query.setInteger(0, userId);
			query.setInteger(1, storyId);
			query.setInteger(2, sequenceId);
			int count = query.list().size();
			if (count == 0) {
				Favourite favourite = new Favourite();
				Sequence sequence = (Sequence) session.get(Sequence.class,
						sequenceId);
				favourite.setSequence(sequence);
				favourite.setStory(sequence.getStory());
				favourite.setUserId(userId);
				session.save(favourite);
			}
			session.getTransaction().commit();
			session.close();
		} catch (Exception e) {
			session.getTransaction().rollback();
			if (session.isOpen()) {
				session.close();
			}
			throw e;
		}
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static final Favourite[] favouriteList(int userId) throws Exception {
		Session session = sessionFactory.openSession();
		try {
			Query query = session
					.createQuery("from Favourite f where f.userId=?");
			query.setInteger(0, userId);
			List list = query.list();
			Hibernate.initialize(list);
			Favourite[] ret = new Favourite[list.size()];
			list.toArray(ret);
			return ret;
		} catch (Exception e) {
			if (session.isOpen()) {
				session.close();
			}
			throw e;
		}
	}

	public static final void flower(int sequenceId) throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		try {
			Sequence sequence = (Sequence) session.load(Sequence.class,
					new Integer(sequenceId));
			sequence.setFlower(sequence.getFlower() + 1);
			session.update(sequence);
			session.getTransaction().commit();
			session.close();
		} catch (Exception e) {
			session.getTransaction().rollback();
			if (session.isOpen()) {
				session.close();
			}
			throw e;
		}
	}

	public static final void egg(int sequenceId) throws Exception {
		Session session = sessionFactory.openSession();
		session.beginTransaction();
		try {
			Sequence sequence = (Sequence) session.load(Sequence.class,
					new Integer(sequenceId));
			sequence.setEgg(sequence.getEgg() + 1);
			session.update(sequence);
			session.getTransaction().commit();
			session.close();
		} catch (Exception e) {
			session.getTransaction().rollback();
			if (session.isOpen()) {
				session.close();
			}
			throw e;
		}
	}
}
